/*
 * @Author: zhangshu
 * @email: shiliang.zhang@tuya.com
 * @LastEditors: Please set LastEditors
 * @file name: app_common.c
 * @Description: 
 * @Copyright: HANGZHOU TUYA INFORMATION TECHNOLOGY CO.,LTD
 * @Company: http://www.tuya.com
 * @Date: 2022-02-08
 * @LastEditTime: 2022-02-08
 */
#include "tal_memory.h"
#include "tal_attribute_rw.h"

#include "app_common.h"

#define ZCL_ID_OFFSET   100

// attribute size 
static const UINT8_T attribute_sizes[] =
{
    #include "attribute-size.h"
};

//get data size
STATIC UINT8_T get_data_size(ZG_ATTR_TYPE_E data_type);
//get data zcl id
STATIC UINT8_T get_data_zcl_id(UINT16_T cluster_id, UINT16_T attribute_id);
//report attribute data
STATIC VOID_T report_attribute_data(UINT8_T endpoint,
                                            UINT16_T cluster_id, 
                                            UINT16_T attribute_id, 
                                            ZG_ATTR_TYPE_E attribute_type, 
                                            UINT8_T qos, 
                                            UINT16_T delay_ms);

/**
 * @brief get data size from data type
 *
 * @param[in] data_type: data type, please refer to ZG_ATTR_TYPE_E
 * @return data size
 */
STATIC UINT8_T get_data_size(ZG_ATTR_TYPE_E data_type)
{ 
    UINT8_T i;
    for (i = 0; (i + 1) < SIZEOF(attribute_sizes); i += 2) {
        if (attribute_sizes[i] == data_type) {
            return attribute_sizes[i + 1];
        }
    }
    return 0;
}

/**
 * @brief get data zcl id
 *
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @return ZCL id
 */
STATIC UINT8_T get_data_zcl_id(UINT16_T cluster_id, UINT16_T attribute_id)
{
    switch(cluster_id) {
        case CLUSTER_TEMP_MEASUREMENT_CLUSTER_ID: {
            switch (attribute_id) {
                case ATTR_TEMP_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_TEMPERATURE;
                }
                case ATTR_TEMP_MIN_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_TEMPERATURE_MIN;
                }
                case ATTR_TEMP_MAX_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_TEMPERATURE_MAX;
                }
                default:
                    break;
            }
            break;
        }
        case CLUSTER_RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER_ID: {
            switch (attribute_id) {
                case ATTR_RELATIVE_HUMIDITY_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_HUMIDITY;
                }
                case ATTR_RELATIVE_HUMIDITY_MIN_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_HUMIDITY_MIN;
                }
                case ATTR_RELATIVE_HUMIDITY_MAX_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_HUMIDITY_MAX;
                }
                default:
                    break;
            }
            break;
        }
        case CLUSTER_ILLUM_MEASUREMENT_CLUSTER_ID: {
            switch (attribute_id) {
                case ATTR_ILLUM_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_ILLUMINANCE;
                }
                case ATTR_ILLUM_MIN_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_ILLUMINANCE_MIN;
                }
                case ATTR_ILLUM_MAX_MEASURED_VALUE_ATTRIBUTE_ID: {
                    return ZCL_ID_ILLUMINANCE_MAX;
                }
                default:
                    break;
            }
            break;
        }
        case CLUSTER_TUYA_SENSOR_CLUSTER_ID: {
            switch (attribute_id) {
                case TUYA_SENSOR_HUMAN_MOTION_STATE_ATTRIBUTE_ID: {
                    return ZCL_ID_HUMAN_MOTION_STATE;
                }
                case TUYA_SENSOR_PRESENCE_TIME_ATTRIBUTE_ID: {
                    return ZCL_ID_PRESENCE_DELAY;
                }
                case TUYA_SENSOR_MOTION_FAR_DETECTION_ATTRUBTE_ID: {
                    return ZCL_ID_MOTION_FAR_DETECTION;
                }
                case TUYA_SENSOR_MOTIONLESS_FAR_DETECTION_ATTRIBUTE_ID: {
                    return ZCL_ID_MOTIONLESS_FAR_DETECTION;
                }
                case TUYA_SENSOR_MOTION_SENSITIVITY_ATTRIBUTE_ID: {
                    return ZCL_ID_MOTION_SENSITIVITY;
                }
                case TUYA_SENSOR_MOTIONLESS_SENSITIVITY_ATTRIBUTE_ID: {
                    return ZCL_ID_MOTIONLESS_SENSITIVITY;
                }
                case TUYA_SENSOR_MOTION_AMPLIT_ATTRIBUTE_ID: {
                    return ZCL_ID_MOTION_AMPLIT;
                }
                case TUYA_SENSOR_MOTIONLESS_AMPLIT_ATTRIBUTE_ID: {
                    return ZCL_ID_MOTIONLESS_AMPLIT;
                }
                case TUYA_SENSOR_COLOR_TEMPERATURE_ATTRIBUTE_ID: {
                    return ZCL_ID_COLOR_TEMPERATURE;
                }
                case TUYA_SENSOR_LED_STATE_ATTRIBUTE_ID: {
                    return ZCL_ID_LED_STATE;
                }
                case TUYA_SENSOR_CURRENT_DISTANCE_ATTRIBUTE_ID: {
                    return ZCL_ID_CURRENT_DISTANCE;
                }
                default:
                    break;
            }
            break;
        }
        default:
            break;
    }
    return 0;
}

/**
 * @brief put attribute paylad into report send buffer
 *
 * @param[out] send_data: send data, please refer to TAL_ZG_SEND_DATA_T
 * @param[in] attribute_num: attribute number
 * @param[in] attribute_id: attribute id
 * @param[in] attribute_type: attribute type, refer to ZG_ATTR_TYPE_E
 * @param[in] data: point to attribute data to be read
 * @return None
 */
VOID_T put_data_into_send_buffer(TAL_ZG_SEND_DATA_T *send_data,
                                           UINT8_T attribute_num,
                                           UINT16_T attribute_id,
                                           ZG_ATTR_TYPE_E attribute_type,
                                           UINT8_T *data)
{
    UINT8_T data_size = get_data_size(attribute_type);
    send_data->data.zg.attr[attribute_num].attr_id = attribute_id;
    send_data->data.zg.attr[attribute_num].type = attribute_type;
    send_data->data.zg.attr[attribute_num].size = data_size;
    for (UINT8_T i = 0; i < data_size; i++) {
        send_data->data.zg.attr[attribute_num].value[i] = (UINT8_T)(*(data+i));
    }
}

/**
 * @brief report attribute data
 * NOTE: only for server clusters attributes
 *
 * @param[in] endpoint: device endpoint id
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @param[in] attribute_type: attribute type, refer to ZG_ATTR_TYPE_E
 * @param[in] qos: send qps, refer to TAL_SEND_QOS_E
 * @param[in] delay_ms: delay send time in ms
 * @return None
 */
STATIC VOID_T report_attribute_data(UINT8_T endpoint,
                                            UINT16_T cluster_id, 
                                            UINT16_T attribute_id, 
                                            ZG_ATTR_TYPE_E attribute_type, 
                                            UINT8_T qos, 
                                            UINT16_T delay_ms)
     {
    // UINT8_T data_size = get_data_size(attribute_type);
    // UINT8_T temp_data[9];//max buffer
    // TAL_ZG_SEND_DATA_T send_data;

    // tal_system_memset(&temp_data, 0, 9);
    // tal_system_memset(&send_data, 0, SIZEOF(TAL_ZG_SEND_DATA_T));

    // //read out, ensure the data same with token
    // tal_zg_read_attribute(endpoint,
    //                       cluster_id,
    //                       attribute_id,
    //                       &temp_data,
    //                       data_size);

    // send_data.delay_time = delay_ms;
    // send_data.random_time = 0;
    // send_data.zcl_id = get_data_zcl_id(cluster_id, attribute_id);
    // send_data.qos = QOS_1;
    // send_data.direction = ZG_ZCL_DATA_SERVER_TO_CLIENT;
    // send_data.frame_type = ZG_ZCL_FRAME_TYPE_GLOBAL;
    // send_data.command_id = CMD_REPORT_ATTRIBUTES_COMMAND_ID;
   
    // // unicast to gateway
    // send_data.addr.mode = SEND_MODE_DEV;
    // send_data.addr.type.dev.dst_addr = TUYA_GATEWAY_ADDRESS;
    // send_data.addr.type.dev.dst_ep = 0x01;
    // send_data.addr.type.dev.src_ep = endpoint;
    // send_data.addr.type.dev.cluster_id = cluster_id;
   
    // send_data.data.zg.attr_sum = 1;
    // put_data_into_send_buffer(&send_data, 0, attribute_id, attribute_type, temp_data);
    // tal_zg_clear_send_data(ZG_CLEAR_ALL_ZCL_ID, &send_data.zcl_id);
    // tal_zg_send_data(&send_data, NULL, 3000);
}

/**
 * @brief read attribute data
 * NOTE: only for server clusters attributes
 *
 * @param[in] endpoint: device endpoint id
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @param[in] data: point to attribute data to be read
 * @param[in] length: length of attribute data
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET read_sensor_attribute(UINT8_T endpoint, 
                                          UINT16_T cluster_id, 
                                          UINT16_T attribute_id, 
                                          VOID_T* data, 
                                          UINT8_T length)
{
    OPERATE_RET status = OPRT_COM_ERROR;
    status = tal_zg_read_attribute(endpoint,
                                   cluster_id,
                                   attribute_id,
                                   (VOID_T *)data,
                                   length);
    return status;
}

/**
 * @brief report sensor attribute
 * NOTE: only for server clusters attributes
 *
 * @param[in] endpoint: device endpoint id
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @param[in] attribute_type: attribute type, refer to ZG_ATTR_TYPE_E
 * @param[in] delay_ms: delay send time in ms
 * @return none
 */
VOID_T report_sensor_attribute(UINT8_T endpoint,
                                        UINT16_T cluster_id, 
                                        UINT16_T attribute_id, 
                                        ZG_ATTR_TYPE_E attribute_type, 
                                        UINT16_T delay_ms)
{
    report_attribute_data(endpoint,
                          cluster_id, 
                          attribute_id, 
                          attribute_type, 
                          QOS_1, 
                          delay_ms);
}

/**
 * @brief write sensor attribute
 * NOTE: only for server clusters attributes
 *
 * @param[in] endpoint: device endpoint id
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @param[in] data: point to attribute data to be write
 * @param[in] length: length of attribute data
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET write_sensor_attribute(UINT8_T endpoint,
                                           UINT16_T cluster_id,
                                           UINT16_T attribute_id, 
                                           VOID_T* data, 
                                           ZG_ATTR_TYPE_E attribute_type)
{
  OPERATE_RET status = OPRT_COM_ERROR;
  status = tal_zg_write_attribute(endpoint,
                                  cluster_id,
                                  attribute_id,
                                  data,
                                  attribute_type);
  return status;
}

/**
 * @description: read app version
 * @param[in] none
 * @return: app version id
 */
UINT8_T read_app_version(VOID_T)
{
    UINT8_T version = 0;
    OPERATE_RET status = OPRT_COM_ERROR;
    status = read_sensor_attribute(IAS_ZONE_ENDPOINT, CLUSTER_BASIC_CLUSTER_ID, ATTR_APPLICATION_VERSION_ATTRIBUTE_ID, &version, SIZEOF(version));
    if (OPRT_OK!=status) {
        return INVALID_UINT8_DATA;
    }
    return version;
}

/**
 * @description: write power source
 * @param[in] source: power source, please refer to POWER_SOURCE_E
 * @return: none
 */
VOID_T write_power_source(POWER_SOURCE_E source)
{
    write_sensor_attribute(IAS_ZONE_ENDPOINT, CLUSTER_BASIC_CLUSTER_ID, ATTR_POWER_SOURCE_ATTRIBUTE_ID, &source, ATTR_ENUM8_ATTRIBUTE_TYPE);
}

